/*
58颗WS2812灯珠做成的7段数码管彩虹效果时钟
每段2颗灯珠，接线顺序B-A-F-E-D-C-G,4位从右到左
===主要代码由DeepSeek生成====
Last Update: 2025/3/6
*/

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <time.h>
#include <FastLED.h>
#include <ArduinoOTA.h>

const char *ssid     = "XXXXX";
const char *password = "XXXXXXXXX"; 
float TimeZone = 28800;                  
const char *TIME_SERVER = "time1.aliyun.com";

#define NUM_LEDS 58
#define DATA_PIN 4  //D4
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
 
uint8_t hour, minute, second;
bool Dots = true;   //冒号

// 彩虹效果参数
uint8_t hueOffset = 0; // 色相偏移量

// 定义7段数码管的段映射
// 每段2颗灯珠，4位数码管，共56颗灯珠
// segmentMap的内容会根据实际接线方式的不同而变化！根据实际接线顺序修改以下映射关系
// 每位数码管的段映射如下：
// 段A: 0-1, 段B: 2-3, 段C: 4-5, 段D: 6-7, 段E: 8-9, 段F: 10-11, 段G: 12-13
const int segmentMap[4][7][2] = {
    { {46,47},{44,45},{54,55},{52,53},{50,51},{48,49},{56,57} },   // 右数第四位
    { {32,33},{30,31},{40,41},{38,39},{36,37},{34,35},{42,43} },  // 右数第三位
    { {16,17},{14,15},{24,25},{22,23},{20,21},{18,19},{26,27} }, // 右数第二位
    { {2,3},{0,1},{10,11},{8,9},{6,7},{4,5},{12,13} },        // 右数第一位
}; 

// 定义数字0-9的段显示
const bool digitMap[10][7] = {
  {1, 1, 1, 1, 1, 1, 0},  // 0
  {0, 1, 1, 0, 0, 0, 0},  // 1
  {1, 1, 0, 1, 1, 0, 1},  // 2
  {1, 1, 1, 1, 0, 0, 1},  // 3
  {0, 1, 1, 0, 0, 1, 1},  // 4
  {1, 0, 1, 1, 0, 1, 1},  // 5
  {1, 0, 1, 1, 1, 1, 1},  // 6
  {1, 1, 1, 0, 0, 0, 0},  // 7
  {1, 1, 1, 1, 1, 1, 1},  // 8
  {1, 1, 1, 1, 0, 1, 1}   // 9
};

const int Doc1 =28;  //冒号
const int Doc2 =29;

void setup() { 
  FastLED.addLeds<WS2812B, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);  
  FastLED.setBrightness(70);  //亮度
  Animation();  //转圈效果
  WiFi.begin(ssid,password);
  delay(500);
  int count = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    count++;
    if(count > 20)
    break;
    delay(500);
    Serial.print(".");
  }
 if (WiFi.status() == WL_CONNECTED)
 {
    Serial.println("connected");
    configTime(TimeZone, 0, TIME_SERVER);
}
  setupOTA();
}

void displayTime(uint8_t hour,uint8_t minute){
  //FastLED.clear();
  time_t now = time(nullptr);            // 获取当前时间戳
  struct tm *timeinfo = localtime(&now); // 转为本地时间

  hour = timeinfo->tm_hour;
  minute = timeinfo->tm_min;
  second = timeinfo->tm_sec;
  
  int hourTens = hour / 10;
  int hourOnes = hour % 10;
  displayDigit(0,hourTens,hueOffset);
  displayDigit(1,hourOnes,hueOffset);

  int minuteTens = minute / 10;
  int minuteOnes = minute % 10;
  displayDigit(2, minuteTens,hueOffset);
  displayDigit(3, minuteOnes,hueOffset);
 
 
  FastLED.show();
}

void displayDots() {
  if(Dots)
  {
    leds[28] = CHSV(hueOffset, 255, 255); // 使用彩虹色
    leds[29] = CHSV(hueOffset, 255, 255); // 使用彩虹色 
   }
  else
    {
    leds[28] = CRGB::Black;
    leds[29] = CRGB::Black; 
    }
  if (second % 2==0) {Dots = false;}
  else {Dots = true;}
  FastLED.show();
}

void displayDigit(int digitIndex,int number,uint8_t hue) {
  for (int segment = 0; segment < 7; segment++) {
    if (digitMap[number][segment]) {
      leds[segmentMap[digitIndex][segment][0]] = CHSV(hue + (digitIndex * 30), 255, 255);
      leds[segmentMap[digitIndex][segment][1]] = CHSV(hue + (digitIndex * 30), 255, 255);
    }
    }
  }


void loop(){
  ArduinoOTA.handle();

  if(second == 0 ){
  FastLED.clear();
  Animation();
  }

  // 更新彩虹效果
  hueOffset += 1; // 每次循环增加色相偏移量
  if (hueOffset >= 255) hueOffset = 0; // 色相范围是0-255

  displayTime(hour,minute);
  displayDots();

  delay(100); // 控制彩虹效果速度
  
}

// 数码管A-G转圈动画效果
void Animation() {
  for (int i = 0; i< 7; i++) {
    // 点亮当前段
    for (int digit = 0; digit < 4; digit++) {
      leds[segmentMap[digit][i][0]] = CHSV(i * 36, 255, 255); // 调整36的值来改变颜色间隔
      leds[segmentMap[digit][i][1]] = CHSV(i * 36, 255, 255); // 调整36的值来改变颜色间隔
    }
    FastLED.show();
    delay(150); // 每段点亮时间

    // 熄灭当前段
    for (int digit = 0; digit < 4; digit++) {
      leds[segmentMap[digit][i][0]] = CRGB::Black;
      leds[segmentMap[digit][i][1]] = CRGB::Black;
    }
    FastLED.show();
  }
}

// 初始化OTA
void setupOTA() {
  ArduinoOTA.setHostname("ESP8266-7Segment"); // 设置设备名称
  ArduinoOTA.setPassword("123456");     // 设置OTA密码（可选）

  ArduinoOTA.onStart([]() {
    Serial.println("OTA更新开始");
    FastLED.clear(); // 清空LED显示
    FastLED.show();
  });

  ArduinoOTA.onEnd([]() {
    Serial.println("\nOTA更新完成");
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("更新进度: %u%%\r", (progress / (total / 100)));
  });

  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("OTA错误[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("认证失败");
    else if (error == OTA_BEGIN_ERROR) Serial.println("开始失败");
    else if (error == OTA_CONNECT_ERROR) Serial.println("连接失败");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("接收失败");
    else if (error == OTA_END_ERROR) Serial.println("结束失败");
  });

  ArduinoOTA.begin();
  Serial.println("OTA初始化完成");
}